package com.eugenema.windowGui.controller;

import com.eugenema.runMain.StartMain;
import com.eugenema.service.UpdateService;
import com.eugenema.util.ConfigUtil;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXDialog;
import com.jfoenix.controls.JFXSpinner;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.Flow;
import io.datafx.controller.flow.FlowHandler;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.ViewFlowContext;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.concurrent.Worker;
import javafx.event.Event;
import javafx.event.EventDispatchChain;
import javafx.event.EventDispatcher;
import javafx.event.EventTarget;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.util.Duration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.PostConstruct;

/**
 * 侧边栏
 *
 * @author Eugenema
 * @date 2023/3/27 22:11
 */
@ViewController(value = "/fxml/sideMenu.fxml", title = "侧边栏")
public class SideMenuController {
    /** 日志 */
    private static Logger logger = LoggerFactory.getLogger(SideMenuController.class);
    /** 更新日志配置 key */
    private static final String CONFIG_UPDATE_LOG_KEY = "config_update_log";

    /** 上下文对象 */
    @FXMLViewFlowContext
    private ViewFlowContext context;
    /** 程序启动时初始化的公共流，对应主界面内容区 */
    private Flow contextFlow;
    /** 程序启动时初始化的公共流控制器，对应主界面内容区 */
    private FlowHandler contextFlowHandler;
    /** 根节点 */
    @FXML
    private StackPane sideMenu;
    /** 图标 */
    @FXML
    private ImageView icon;
    /** 首页 */
    @FXML
    private Label homeDetail;
    /** 程序配置 */
    @FXML
    private Label programSetting;
    /** 菜单项 */
    @FXML
    private VBox menuList;
    /** 版本号 */
    @FXML
    private Label version;
    /** 升级信息弹窗 */
    @FXML
    private JFXDialog dialog;
    /** 弹窗网页浏览元素 */
    @FXML
    private WebView webView;
    /** 检查更新按钮 */
    @FXML
    private JFXButton updateCheck;
    /** 升级弹窗加载进度条 */
    @FXML
    private JFXSpinner loading;

    /**
     * 加载初始化
     *
     * @author Eugenema
     * @date 2023/11/6 22:10
     *
     **/
    @PostConstruct
    public void init() {
        // 移除弹窗
        sideMenu.getChildren().remove(dialog);
        // 将进度条添加到 WebView 上方，并设置 WebView 和进度条的样式
        dialog.getChildren().add(loading);
        loading.setVisible(false);

        //加载图标
        Image image = new Image(getClass().getResourceAsStream("/logo/logo.png"));
        icon.setImage(image);

        //初始化主界面内容区的流和流控制器
        contextFlow = (Flow) context.getRegisteredObject(MainController.CONTEXT_KEY_FLOW);
        contextFlowHandler = (FlowHandler) context.getRegisteredObject(MainController.CONTEXT_KEY_FLOW_HANDLER);

        //绑定菜单项与界面的连接
        //1、绑定“首页”菜单项
        bindNodeToController(homeDetail, HomeDetailController.class, contextFlow);
        //2、绑定“程序配置”菜单项
        bindNodeToController(programSetting, SettingController.class, contextFlow);

        //菜单项绑定事件处理器
        //1、绑定“首页”菜单项
        homeDetail.setEventDispatcher(new LabelEventDispatcher(homeDetail));
        //2、绑定“程序配置”菜单项
        programSetting.setEventDispatcher(new LabelEventDispatcher(programSetting));

        //默认选中第一个菜单项
        Node node = menuList.getChildren().get(0);
        node.fireEvent(
                new MouseEvent(
                        MouseEvent.MOUSE_CLICKED, node.getLayoutX(), node.getLayoutY(),
                        0, 0, MouseButton.PRIMARY, 1, true,
                        true, true, true, true,
                        false, false, true,
                        false, false, null
                )
        );

        // 绑定“更新内容”弹窗关闭监听事件
        dialog.setOnDialogClosed(e -> {
            // 清空之前加载的内容
            webView.getEngine().loadContent("");
        });

        // 设置版本号并绑定检查更新方法
        version.setText("V" + UpdateService.nowVersionInfo.getVersionMain());
        version.setOnMouseClicked(event -> {
            // 显示“更新内容“弹窗
            showUpdateInfoDialog();
        });
    }

    private void bindNodeToController(Node node, Class<?> controllerClass, Flow flow) {
        flow.withGlobalLink(node.getId(), controllerClass);
    }

    /**
     * 菜单项点击事件
     * 将点击的菜单更改背景色，其他未点击的菜单去除背景色，达到选中状态
     *
     * @param event 点击事件
     * @author Eugenema
     * @date 2023/4/9 12:10
     **/
    @FXML
    private void handleLabelClicked(MouseEvent event) {
        /** 点击的元素 */
        EventTarget target = event.getTarget();
        if (target instanceof Label) {
            Label clickedLabel = (Label) target;
            //清空所有 label 的背景色
            for (Node child : menuList.getChildren()) {
                child.setStyle("-fx-background-color: transparent;");
            }

            //设置点击的 label 的背景色
            clickedLabel.setStyle("-fx-background-color: #fcfdff;");

            //切换界面
            StartMain.threadPool.submit(() ->
                    Platform.runLater(() -> {
                        try {
                            contextFlowHandler.handle(clickedLabel.getId());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    })
            );
        }
    }

    /**
     * Label 事件处理器
     * 确保 Label 的点击事件，mouseEvent 参数能够拿到 Label 元素，而不是其子元素
     *
     * @author Eugenema
     * @date 2023/4/9 12:58
     **/
    class LabelEventDispatcher implements EventDispatcher {
        private final Label label;

        public LabelEventDispatcher(Label label) {
            this.label = label;
        }

        @Override
        public Event dispatchEvent(Event event, EventDispatchChain tail) {
            if (event.getTarget() instanceof Label) {
                return tail.dispatchEvent(event);
            } else {
                if (event instanceof MouseEvent) {
                    MouseEvent mouseEvent = (MouseEvent) event;
                    return tail.dispatchEvent(new MouseEvent(
                            label, label, mouseEvent.getEventType(), mouseEvent.getX(), mouseEvent.getY(),
                            mouseEvent.getScreenX(), mouseEvent.getScreenY(),
                            mouseEvent.getButton(), mouseEvent.getClickCount(),
                            mouseEvent.isShiftDown(), mouseEvent.isControlDown(),
                            mouseEvent.isAltDown(), mouseEvent.isMetaDown(),
                            mouseEvent.isPrimaryButtonDown(),
                            mouseEvent.isMiddleButtonDown(),
                            mouseEvent.isSecondaryButtonDown(),
                            mouseEvent.isSynthesized(), mouseEvent.isPopupTrigger(),
                            mouseEvent.isStillSincePress(), mouseEvent.getPickResult()
                    ));
                }
                return event;
            }
        }
    }

    /**
     * 检查更新
     *
     * @author Eugenema
     * @date 2023/10/31 22:44
     **/
    @FXML
    public void checkVersion() {
        logger.info("开始检查更新……");
        // 隐藏“更新内容”弹窗
        dialog.close();
        // 禁用：操作区域、侧边栏区
        MainController.switchNode(false, (StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_SIDE_MENU), (StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_MAIN_CONTENT));
        StartMain.threadPool.submit(() -> {
            // 等待检查更新返回值，动态禁用/启用：操作区域、侧边栏区
            MainController.switchNode(UpdateService.updateCheck(), (StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_SIDE_MENU), (StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_MAIN_CONTENT));
        });
    }

    /**
     * 显示“更新内容”弹窗
     *
     * @author Eugenema
     * @date 2023/11/6 22:36
     *
     *
     * @return
     **/
    public void showUpdateInfoDialog() {
        WebEngine webEngine = webView.getEngine();

        // 创建一个时间轴动画，随着网页加载进度改变进度条的值
        Timeline timeline = new Timeline(new KeyFrame(Duration.ZERO, progressBar -> {
            // 获取加载进度
            double progress = webEngine.getLoadWorker().getProgress();
            // 设置进度条的进度值
            loading.setProgress(progress);
            // 设置动画持续时间为5秒
        }), new KeyFrame(Duration.seconds(0.1)));
        // 设置循环播放动画并显示进度条
        loading.setVisible(true);
        timeline.setCycleCount(Animation.INDEFINITE);
        timeline.play();

        // 在网页加载完成后停止动画并隐藏进度条
        webEngine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
            if (newValue == Worker.State.SUCCEEDED) {
                timeline.stop();
                loading.setVisible(false);
            }
        });

        // 加载网页并展示弹窗
        webEngine.load(ConfigUtil.getProperty(CONFIG_UPDATE_LOG_KEY));
        dialog.setTransitionType(JFXDialog.DialogTransition.CENTER);
        dialog.show((StackPane) context.getRegisteredObject(MainController.CONTEXT_KEY_HOME_CONTENT));
    }
}
